/* Written and copyright 2001-2003 Benjamin Kohl.
 * Distributed under the GNU General Public License; see the README file.
 * This code comes with NO WARRANTY.
 */
package jhttpp2;

import java.io.BufferedInputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Set;
import java.util.TreeSet;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;

import p2p.P2pClientThread;
import jhttpp2.Jhttpp2Server;
/**
	File: Jhttpp2Read.java
	reads from a Jhttpp2ClientInputStream and writes to the BufferedOutputStream

	@author Benjamin Kohl
*/
public class Jhttpp2Read extends Thread {
	public static final int BUFFER_SIZE=96000;
	private BufferedInputStream in;
	private BufferedOutputStream out;
	private Jhttpp2HTTPSession connection;
	private static Jhttpp2Server server;
	
	public static HashMap< String, Integer > lockUrl;
	
	BufferedOutputStream fos;
	MessageDigest messageDigest;

	public Jhttpp2Read(Jhttpp2Server server,Jhttpp2HTTPSession connection,BufferedInputStream l_in, BufferedOutputStream l_out) {
          in=l_in;
          out=l_out;
          this.connection=connection;
          this.server=server;
          setPriority(Thread.MIN_PRIORITY);
          start();
	}
	public void run() {
          read();
	}
	
	public static String hashString(String url) {
		MessageDigest md;
		String hexStr = "";
		try {
			hexStr = "";
			md = MessageDigest.getInstance("SHA1");
			md.reset();
			byte[] buffer = url.getBytes();
			md.update(buffer);
			byte[] digest = md.digest();

			for (int i = 0; i < digest.length; i++) {
				hexStr +=  Integer.toString( ( digest[i] & 0xff ) + 0x100, 16).substring( 1 );
			}
//			System.out.println(hexStr);
		} catch (NoSuchAlgorithmException e) {
			// TODO Auto-generated catch block
			hexStr = "hash_error";
			e.printStackTrace();
		}
			
		return hexStr;
	}
	
	public static long findFile(String name, File file) {
        File[] list = file.listFiles();
        if(list!=null)
        for (File fil : list)
        {
            if (fil.isDirectory()) {
                findFile(name,fil);
            }
            else if (name.equalsIgnoreCase(fil.getName())) {
//                System.out.println("oke find this file:" + name);
                return fil.length();
            }
        }
        
        return 0;
    }
	
	public static long searchExistCache(String url) {
		String hashUrl = hashString(url);
		String filename =  hashUrl + ".cache";
        String directory = "data/";
        
        if ( Jhttpp2Read.lockUrl.containsKey( hashUrl ) ) {
        	return 0;
        } else {
        	//return size of file. if have file and size > 0 oke read cache
        	return findFile(filename,new File(directory));
        }
	}
	
	private void read(){
	    int bytes_read=0;
	    byte[] buf=new byte[BUFFER_SIZE];
	    boolean flagwrite = false;
	    
	    try {
	    	String hexStr = "";
			if( !this.connection.in.ssl && this.connection.in.methodID == 0 ){
		    	hexStr = hashString(connection.getJhttpp2ClientInputStream().getFullURL());
		    	if( !Jhttpp2Read.lockUrl.containsKey(hexStr) && !P2pClientThread.urlwait.containsKey(hexStr) ) {
					fos = new BufferedOutputStream( new FileOutputStream("data/" + hexStr + ".cache") );
					//lock this url for write cache
					Jhttpp2Read.lockUrl.put(hexStr, 1);
	//				System.out.println("lock url: " + hexStr);
					flagwrite = true;
		    	}
	    	}
	    	while(true) {
	    		bytes_read=in.read(buf);
	    		if (bytes_read!=-1) {
//	    			out.write(buf,0,bytes_read);
//	    			System.out.println(connection.getJhttpp2ClientInputStream().getFullURL());
    	
	    			// if can not find the file in folder, create new cache
//	    			if( !searchExistCache(connection.getJhttpp2ClientInputStream().getFullURL()) )
	    				
	    			if( !this.connection.in.ssl && this.connection.in.methodID == 0 ){
	    				if( flagwrite ) {
		    				try{
				    			fos.write(buf,0,bytes_read);
				    			fos.flush();
		    				} catch (NullPointerException npe ) {
		    					
		    				}	
	    				}
	    			}
    	
	    			out.write(buf,0,bytes_read);
	    	        out.flush();
	    	        server.addBytesRead(bytes_read);
	    	        
	    		} else {
	    			if( !this.connection.in.ssl && this.connection.in.methodID == 0 ){
	    				if( flagwrite ) {
		    				try{
//		    					System.out.println("READ: write cache");
		    					fos.flush();
				    			fos.close();
		    				} catch (NullPointerException npe ) {
		    					
		    				}	
	    				}
	    			}
	    			break;
	    		}
	    	}
	    	
	    	if( !this.connection.in.ssl && this.connection.in.methodID == 0 ){
	    		if( flagwrite ) {
	    			Jhttpp2Read.lockUrl.remove(hexStr);
	    		}
	    	}
	    } catch (IOException e) {}

	    try {
	    	if (connection.getStatus()!=connection.SC_CONNECTING_TO_HOST) // *uaaahhh*: fixes a very strange bug
	    		connection.getLocalSocket().close();
	    	// why? If we are connecting to a new host (and this thread is already running!) , the upstream
	    	// socket will be closed. So we get here and close our own downstream socket..... and the browser
	    	// displays an empty page because jhttpp2
	    	// closes the connection..... so close the downstream socket only when NOT connecting to a new host....
	    }
	    catch(IOException e_socket_close) {}
	}
	
	public void close() {
		try {
			in.close();
		}
		catch (Exception e) {}
	}
}


